package me.yushuai.wukong.base.service.impl;

import me.yushuai.wukong.base.api.dto.CreateHsCodeDTO;
import me.yushuai.wukong.base.api.dto.HsCodeDTO;
import me.yushuai.wukong.base.api.dto.UpdateHsCodeDTO;
import me.yushuai.wukong.base.entity.HsCode;
import me.yushuai.wukong.base.mapper.HsCodeMapper;
import me.yushuai.wukong.base.repository.HsCodeRepository;
import me.yushuai.wukong.base.service.HsCodeService;
import me.yushuai.wukong.common.api.AbstractPageable;
import me.yushuai.wukong.common.dto.PageDTO;
import me.yushuai.wukong.common.error.WuKongException;
import me.yushuai.wukong.common.exceptin.NotExistException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

/**
 * 海关编码业务实现类
 *
 * @author zhoushuai@189.cn
 * @since 2022-08-25
 */
@Service
public class HsCodeServiceImpl implements HsCodeService {

    private final HsCodeRepository hsCodeRepository;

    private final HsCodeMapper hsCodeMapper;

    @Autowired
    public HsCodeServiceImpl(HsCodeRepository hsCodeRepository, HsCodeMapper hsCodeMapper) {
        this.hsCodeRepository = hsCodeRepository;
        this.hsCodeMapper = hsCodeMapper;
    }

    @Override
    public Long createHsCode(CreateHsCodeDTO createHsCodeDTO) throws WuKongException {
        //1. 检查海关编码是存在
        final String code = createHsCodeDTO.getHsCode();
        this.assertHsCodeNotExist(code);

        //2. 新增海关编码
        final HsCode hsCode = this.hsCodeMapper.mapper(createHsCodeDTO);
        this.hsCodeRepository.save(hsCode);
        return hsCode.getHsCodeId();
    }

    @Override
    public Long updateHsCode(UpdateHsCodeDTO updateHsCodeDTO) throws WuKongException {

        //1. 检查海关编码是否存在
        final Long hsCodeId = updateHsCodeDTO.getHsCodeId();
        final String code = updateHsCodeDTO.getHsCode();
        this.assertHsIdAndHsCodeMatching(hsCodeId, code);

        //2. 通过海关编码编号更新海关编码信息
        final HsCode hsCode = this.hsCodeMapper.mapper(updateHsCodeDTO);
        this.hsCodeRepository.save(hsCode);

        return updateHsCodeDTO.getHsCodeId();
    }

    @Override
    public void deleteHsCode(Long hsCodeId) throws WuKongException {
        //1. 检查海关编码是否存在
        this.assertHsCodeIdExist(hsCodeId);

        //2. 删除海关编码记录
        this.hsCodeRepository.deleteById(hsCodeId);
    }

    @Override
    public HsCodeDTO findOne(Long hsCodeId) throws WuKongException {

        //1. 通过hsCodeId查询海关编码信息
        final HsCode hsCode = this.hsCodeRepository.findById(hsCodeId)
                //2. 检查海关编码信息是否存在并抛出异常
                .orElseThrow(() -> new NotExistException(hsCodeId, HsCode.class));

        //3. 返回查询结果
        return this.hsCodeMapper.mapper(hsCode);
    }

    @Override
    public PageDTO<HsCodeDTO> pagingSearchHsCode(AbstractPageable page, Specification<HsCode> spec) {

        // 1. 分页对象转换为mybatis的分页对象
        Pageable pageable = PageRequest.of(page.getCurrent(), page.getSize());
        Specification<HsCode> querySpec = spec;
        if (Objects.isNull(querySpec)) {
            querySpec = (root, query, criteriaBuilder) -> query.getRestriction();
        }

        //3. 执行查分页查询操作
        final Page<HsCode> hsCodePage = this.hsCodeRepository.findAll(querySpec, pageable);

        //4. 转换DO对象为DTO对象
        final List<HsCodeDTO> hsCodeDtoList = this.hsCodeMapper.mapper(hsCodePage.getContent());

        //5. 新建返回值并返回
        page.setTotal(hsCodePage.getTotalElements());
        return PageDTO.of(page, hsCodeDtoList);
    }

    @Override
    public void assertHsCodeIdExist(Long hsCodeId) throws WuKongException {
        if (!this.hsCodeRepository.existsById(hsCodeId)) {
            throw new NotExistException(hsCodeId, HsCode.class);
        }
    }

    @Override
    public void assertHsCodeExist(String hsCode) throws WuKongException {
        //1. prepare query condition
        final Specification<HsCode> spec = (root, query, criteriaBuilder) -> criteriaBuilder.and(
                criteriaBuilder.equal(root.get("hsCode").as(String.class), hsCode)
        );

        //2. if the hsCode not exist throw exception
        if (this.hsCodeRepository.count(spec) == 0) {
            throw new NotExistException(hsCode, "HsCode.hsCode");
        }
    }

    @Override
    public void assertHsCodeNotExist(String hsCode) throws WuKongException {
        //1. prepare query condition
        final Specification<HsCode> spec = (root, query, criteriaBuilder) -> criteriaBuilder.and(
                criteriaBuilder.equal(root.get("hsCode").as(String.class), hsCode)
        );

        //2. if the hsCode exists throw exception
        if (this.hsCodeRepository.count(spec) > 0) {
            throw new WuKongException("HsCode.hsCode.notFound", hsCode);
        }
    }

    @Override
    public void assertHsIdAndHsCodeMatching(Long codeId, String code) throws WuKongException {
        final Specification<HsCode> spec = (root, query, criteriaBuilder) -> criteriaBuilder.and(
                criteriaBuilder.equal(root.get("codeId").as(Long.class), codeId),
                criteriaBuilder.equal(root.get("hsCode").as(String.class), code)
        );

        if (this.hsCodeRepository.count(spec) == 0) {
            throw new WuKongException("HsCode.HsIdAndHsCode.notMatch", new Object[]{codeId, code});
        }
    }


}




